package server;


import java.math.BigInteger;
import java.rmi.RemoteException;
import java.util.ArrayList;

import Log.*;

import interfaces.Master;

public class PrimeWorker {
	private ArrayList<ComputedJob> computedJobArray = new ArrayList<ComputedJob>();	
	private Master master = null;
	
	public void setMaster(Master master) {
		this.master = master;
	}

	public void compute() throws RemoteException {

		//System.out.println("worker:list all records before cleanup");
		// print();
		
		Log.log(MessageType.Worker, "cleanComputedJobs...");
		cleanComputedJobs();
		
		//System.out.println("worker:list all records after cleanup");
		//print();

		master.sendComputed(computedJobArray);
		while (true) {
			Job job = master.getJob();
			ComputedJob cpJob = computeJob(job);
			System.out.println(job.a + " " + job.N + " " + cpJob.c_result);
			computedJobArray.add(cpJob);
			master.returnResult(job, !cpJob.c_result);
						
			
		}
	}
	
	
	
	// keep items with last N, delete items with the other N
	private void cleanComputedJobs(){
		int size = computedJobArray.size();
		if (size > 0 ){ 
		   BigInteger lastN =  computedJobArray.get(size - 1).c_n;
		   //System.out.println("lastN:"+lastN);
		   while (true)
		   {
			BigInteger currentN = computedJobArray.get(0).c_n;
			
			if (!currentN.equals(lastN) )
			 {computedJobArray.remove(0);}
			 else
			 {break;}	
		    }
		} 
	}
	
	// list all items in computecJobArray
	private void print()
	{
		
		for (ComputedJob item:computedJobArray)
		{
			System.out.println("computedJobArray: n:"+item.c_n + ", a:"+ item.c_a);
		}	
		
	}

	private ComputedJob computeJob(Job j){
	        boolean result = miller_rabin_pass(j.a, j.N);
	        ComputedJob cj = new ComputedJob(j.a,j.N,result);
	        return cj;	
	}
	
    private boolean miller_rabin_pass(BigInteger a, BigInteger N) {
        BigInteger n_minus_one = N.subtract(BigInteger.ONE);
        BigInteger d = n_minus_one;
     	int s = d.getLowestSetBit();
	    d = d.shiftRight(s);

        BigInteger a_to_power = a.modPow(d, N);
        if (a_to_power.equals(BigInteger.ONE)) return true;
        for (int i = 0; i < s-1; i++) {
            if (a_to_power.equals(n_minus_one)) return true;
            a_to_power = a_to_power.multiply(a_to_power).mod(N);
        }
        if (a_to_power.equals(n_minus_one)) return true; //possibly a prime
        return false;  //is a composite
    }
}   